//译码模块ID
`include "ysyx_22040339_define.v"

module ysyx_22040339_IDU(
    input clk,
    input [`ysyx_22040339_DATA_WIDTH-1:0] pc,
    input [31:0] inst,
    input wb_reg_wen,
    input [4:0] wb_rd,
    input [`ysyx_22040339_DATA_WIDTH-1:0] wb_data,
    output [`ysyx_22040339_DATA_WIDTH-1:0] op1,
    output [`ysyx_22040339_DATA_WIDTH-1:0] op2,
    output [`ysyx_22040339_DATA_WIDTH-1:0] jump_add1,
    output [`ysyx_22040339_DATA_WIDTH-1:0] jump_add2,
//    output [`ysyx_22040339_DATA_WIDTH-1:0] imm,
    output [`ysyx_22040339_FN_WIDTH-1:0] alu_fn,
    output [2:0] ls_size,
    output op_dw,
    output jump,
    output branch,
    output mem2reg,
    output mem_read,
    output mem_write,
    output reg_write,
    output [4:0] rd,
    output [`ysyx_22040339_DATA_WIDTH-1:0] store_data,
    output inst_error,
    output ebreak
);
    wire [6:0] opc;
    assign opc = inst[6:0];
    wire [4:0] rd;
    assign rd = inst[11:7]; 
    wire [2:0] func3 = inst[14:12];
    wire [4:0] rs1 = inst [19:15];
    wire [4:0] rs2 = inst [24:20];
    wire [6:0] func7 = inst [31:25];
    wire [`ysyx_22040339_DATA_WIDTH-1:0] src1;
    wire [`ysyx_22040339_DATA_WIDTH-1:0] src2;
    //产生I、U、S、B、J五种立即数
    wire [`ysyx_22040339_DATA_WIDTH-1:0] immI = {{(`ysyx_22040339_DATA_WIDTH-12){inst[31]}},inst[31:20]};
    wire [`ysyx_22040339_DATA_WIDTH-1:0] immU = {{(`ysyx_22040339_DATA_WIDTH-32){inst[31]}},inst[31:12],{12{1'b0}}};
    wire [`ysyx_22040339_DATA_WIDTH-1:0] immS = {{(`ysyx_22040339_DATA_WIDTH-20){inst[31]}},inst[31:25],inst[11:7]};
    wire [`ysyx_22040339_DATA_WIDTH-1:0] immB = {{(`ysyx_22040339_DATA_WIDTH-12){inst[31]}},inst[7],inst[30:25],inst[11:8],1'b0};
    wire [`ysyx_22040339_DATA_WIDTH-1:0] immJ = {{(`ysyx_22040339_DATA_WIDTH-20){inst[31]}},inst[19:12],inst[20],inst[30:21],1'b0};
    //指令类型提取
    wire I_type = ((opc == 7'b0000011) & (func3 != 3'b111)) | ((opc == 7'b1100111) & (func3 == 3'b0)) | (opc == 7'b0010011) | ((opc == 7'b0011011) & ((func3 == 3'b0) | (func3 == 3'b001) | (func3 == 3'b101)));
    wire U_type = (opc == 7'b0010111) | (opc == 7'b0110111);
    wire S_type = (opc == 7'b0100011) & ((func3 == 3'b0) | (func3 == 3'b001) | (func3 == 3'b010) | (func3 == 3'b011));
    wire B_type = (opc == 7'b1100011) & ((func3 != 3'b010) | (func3 != 3'b011));
    wire J_type = (opc == 7'b1101111);
    wire R_type = (opc == 7'b0111011) | (opc == 7'b0110011);
    wire N_type = (opc == 7'b1110011);
    wire NOP_type = (inst == 32'h1);

    wire reg_write = U_type | J_type | I_type | R_type;
    wire src_r1 = I_type | S_type | B_type | R_type;
    wire src_r2 = B_type | R_type;
    //运算类型
    wire fn_add;
    wire fn_sub;
    wire fn_sl;
    wire fn_seq;
    wire fn_sne;
    wire fn_xor;
    wire fn_sr;
    wire fn_or;
    wire fn_and;
    wire fn_sra;
    wire fn_slt;
    wire fn_sge;
    wire fn_sltu;
    wire fn_sgeu;
    wire fn_div;
    wire fn_divu;
    wire fn_rem;
    wire fn_remu;
    wire fn_mul;
    wire fn_mulh;
    wire fn_mulhsu;
    wire fn_mulhu;
    //通用寄存器
    ysyx_22040339_RegisterFile #(5, 64) ysyx_22040339_RegFile (
        .clk(clk),
        .wdata(wb_data),
        .waddr(wb_rd),
        .wen(wb_reg_wen),
        .raddr1(rs1),
        .raddr2(rs2),
        .rdata1(src1),
        .rdata2(src2)
    );

    assign inst_error = ~(I_type | U_type | S_type | B_type | J_type | R_type | N_type | NOP_type);
    assign jal = J_type;
    assign jalr = I_type & inst[2];
    assign jump = jal | jalr;
    assign branch = B_type;
    assign mem2reg = I_type & ~inst[4] & ~inst[2];
    assign mem_read = mem2reg;
    assign mem_write = S_type;
    assign store_data = src2;
    assign op1 = (jalr | jal) ? 64'b100 : (src_r1 ? src1 : immU);
    assign op2 = (jalr | jal | (U_type & ~inst[5])) ? pc : (src_r2 ? src2 : (I_type ? immI : (U_type ? 64'b0 : immS)));
    assign jump_add1 = J_type ? immJ : (B_type ? immB : src1);
    assign jump_add2 = jalr ? immI : pc;
    assign ls_size = inst[14:12];
    assign op_dw = (I_type | R_type) & inst[3];
    assign ebreak = N_type & (inst[19:7] == 13'b0) & inst[20] & (inst[31:21] == 11'b0);

    assign fn_add = mem_read | mem_write | jal | jalr | U_type | (I_type & (func3 == 3'b0)) | (R_type & (func3 == 3'b0) & (~inst[30] & ~inst[25]));
    assign fn_sub = R_type & inst[30] & (func3 == 3'b0);
    assign fn_sl = (I_type & (func3 == 3'b001) & inst[4]) | (R_type & (func3 == 3'b001) & ~inst[25]);
    assign fn_seq = B_type & (func3 == 3'b0);
    assign fn_sne = B_type & (func3 == 3'b001);
    assign fn_xor = (I_type & (func3 == 3'b100) & inst[4]) | (R_type & (func3 == 3'b100) & ~inst[25]); 
    assign fn_sr = (I_type & (func3 == 3'b101) & ~inst[30] & inst[4]) | (R_type & (func3 == 3'b101) & ~inst[30] & ~inst[25]);
    assign fn_or = (I_type & (func3 == 3'b110) & inst[4]) | (R_type & (func3 == 3'b110) & ~inst[25]);
    assign fn_and = (I_type & (func3 == 3'b111)) | (R_type & (func3 == 3'b111) & ~inst[25]);
    assign fn_sra = (I_type & (func3 == 3'b101) & inst[30] & inst[4]) | (R_type & (func3 == 3'b101) & inst[30]);
    assign fn_slt = (I_type & (func3 == 3'b010) & inst[4]) | (R_type & (func3 == 3'b010) & ~inst[25]) | (B_type & (func3 == 3'b100));
    assign fn_sge = B_type & (func3 == 3'b101);
    assign fn_sltu = (I_type & (func3 == 3'b011) & inst[4]) | (R_type & (func3 == 3'b011) & ~inst[25]) | (B_type & (func3 == 3'b110));
    assign fn_sgeu = B_type & (func3 == 3'b111);
    assign fn_div = R_type & (func3 == 3'b100) & inst[25];
    assign fn_divu = R_type & (func3 == 3'b101) & inst[25];
    assign fn_rem = R_type & (func3 == 3'b110) & inst[25];
    assign fn_remu = R_type & (func3 == 3'b111) & inst[25];
    assign fn_mul = R_type & (func3 == 3'b0) & inst[25];
    assign fn_mulh = R_type & (func3 == 3'b001) & inst[25];
    assign fn_mulhsu = R_type & (func3 == 3'b010) & inst[25];
    assign fn_mulhu = R_type & (func3 == 3'b011) & inst[25];

    assign alu_fn[4] = fn_rem | fn_remu | fn_mul | fn_mulh | fn_mulhsu | fn_mulhu | fn_div | fn_divu;
    assign alu_fn[3] = fn_seq | fn_sne | fn_slt | fn_sge | fn_sltu | fn_sgeu;
    assign alu_fn[2] = fn_sra | fn_xor | fn_sr | fn_or | fn_sltu | fn_sgeu | fn_div | fn_divu | fn_mulhsu | fn_mulhu;
    assign alu_fn[1] = fn_sl  | fn_and | fn_sr | fn_or | fn_slt | fn_sge | fn_div | fn_divu | fn_mul | fn_mulh;
    assign alu_fn[0] = fn_sub | fn_and | fn_xor | fn_or | fn_sne | fn_sge | fn_sgeu | fn_divu | fn_remu | fn_mulh | fn_mulhu;   

endmodule